﻿#region Copyright
/// <copyright>
/// Copyright (c) 2008 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Osh.Dvb
{
	public class TextEncoding
	{
		private static TextEncoding _default = new TextEncoding();
		
		private char[] _controlChars =
			("\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008D\u008E\u008F" +
			 "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E\u009F")
				.ToCharArray();

		private Regex _controlCharsRegex = new Regex("[\u0080-\u009F]", RegexOptions.Compiled);

		public static TextEncoding Default
		{
			get { return _default; }
		}

		public string GetString(BinaryReader reader, int length, int languageCode)
		{
			return GetString(reader, length, (LanguageCode)languageCode);
		}

		public string GetString(BinaryReader reader, int length, LanguageCode languageCode)
		{
			if(length <= 0)
				return string.Empty;

			byte[] bytes = reader.ReadBytes(length);
			return GetString(bytes, languageCode);
		}

		public string GetString(byte[] bytes, LanguageCode languageCode)
		{
			return GetString(bytes, 0, bytes.Length, languageCode);
		}

		public string GetString(byte[] bytes, int offset, int length, LanguageCode languageCode)
		{
			Encoding encoding = null;
			byte firstByte = bytes[offset];
			int codePage = 28591;  // default codepage - iso-8859-1 (Latin I)
			switch(firstByte)
			{
				case 0x01: codePage = 28595; break; // iso-8859-5 (Cyrillic)
				case 0x02: codePage = 28596; break; // iso-8859-6 (Arabic)
				case 0x03: codePage = 28597; break; // iso-8859-7 (Greek)
				case 0x04: codePage = 28598; break; // iso-8859-8 (Hebrew)
				case 0x05: codePage = 28599; break; // iso-8859-9 (Turkish - Latin 5)
				case 0x06: break;                   // iso-8859-10 (Lappish/Nordic/Eskimo - Latin6)
				case 0x07: codePage = 874; break; // iso-8859-11 (Thai)
				case 0x08: break;                   // iso-8859-12 (???)
				case 0x09: break;                   // iso-8859-13 (???)
				case 0x0A: break;                   // iso-8859-14 (???)
				case 0x0B: codePage = 28605; break; // iso-8859-15 (Latin 9)
			}

			// Fix for HorBird "Cyfrowy Polsat"
			if(languageCode == LanguageCode.Pol && codePage == 28591)
				codePage = 28592;

			encoding = Encoding.GetEncoding(codePage);

			string result = (firstByte >= 0x20) ?
				encoding.GetString(bytes, offset, length) :
				encoding.GetString(bytes, offset + 1, length - 1);

			return TranslateText(result, languageCode, codePage);
		}

		private string TranslateText(string sourceString, LanguageCode languageCode, int codePage)
		{
			// Fix for HorBird "CYFRA +"
			if(languageCode == LanguageCode.Pol && codePage == 28595)
			{
				StringBuilder sb = new StringBuilder(sourceString);
				sb.Replace("\u042EA", "\u0104"); // \u00CE
				sb.Replace("\u042Ea", "\u0105"); // \u00CE
				sb.Replace("\u0422C", "\u0106"); // \u00C2
				sb.Replace("\u0422c", "\u0107"); // \u00C2
				sb.Replace("\u042EE", "\u0118"); // \u00CE
				sb.Replace("\u042Ee", "\u0119"); // \u00CE
				sb.Replace('\u0428', '\u0141');  // \u010C
				sb.Replace('\u0448', '\u0142');  // \u010D
				sb.Replace('\u0458', '\u0142');  // \u0159
				sb.Replace("\u0422N", "\u0143"); // \u00C2
				sb.Replace("\u0422n", "\u0144"); // \u00C2
				sb.Replace("\u0422O", "\u00D3"); // \u00C2
				sb.Replace("\u0422o", "\u00F3"); // \u00C2
				sb.Replace("\u0422S", "\u015A"); // \u00C2
				sb.Replace("\u0422s", "\u015B"); // \u00C2
				sb.Replace("\u0422Z", "\u0179"); // \u00C2
				sb.Replace("\u0422z", "\u017A"); // \u00C2
				sb.Replace("\u0427Z", "\u017B"); // \u00C7
				sb.Replace("\u0427z", "\u017C"); // \u00C7
				sourceString = sb.ToString();
			}

			int index = sourceString.IndexOfAny(_controlChars);
			if(index != -1)
			{
				index = sourceString.IndexOf('\u008A');
				if(index != -1)
				{
					// Remove 0x8A control char with CR/LF
					sourceString = sourceString.Replace("\u008A", "\r\n");
				}

				index = sourceString.IndexOfAny(_controlChars);
				if(index != -1)
				{
					// Remove every other control chars
					sourceString = _controlCharsRegex.Replace(sourceString, string.Empty);
				}
			}
			return sourceString;
		}


	}
}
